package service;

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Calendar;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;

import bean.Mail;
import bean.User;
import dao.MailManagerDaoImpl;
import dao.UserManagerDaoImpl;

public class SmtpServer extends Thread {
	private static volatile boolean ok;
	private static ServerSocket s = null;
	private static Socket socket = null;
	public static boolean getOk() {
		return ok;
	}
	public void run() {
		if (ok) return ;
		ok = true;
		Server.open();
		try {
			s = new ServerSocket(25);
			while (ok) {
				socket = s.accept();
				if (!ok) break;
				new Server(socket).start();
			}
			if(socket != null) socket.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	public static void close() {
		ok = false;
		try {
			if(s != null) s.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Server.close();
	}
	public static void main(String[] args) {
		new SmtpServer().start();
		int i;
		Scanner scan= new Scanner(System.in);
		while (true) {
			i=scan.nextInt();
			System.out.println(i);
			if (i==1) {
				SmtpServer.close();
				break;
			}
		}
	}
}
class Server extends Thread{
	private Socket socket;
	private static volatile boolean close_all;
	private static Base64.Decoder decoder = Base64.getDecoder();
	private static Base64.Encoder encoder = Base64.getEncoder();
	private static String domainName = "seatang.cn";
	private static UserManagerDaoImpl userimpl=new UserManagerDaoImpl();
	private static MailManagerDaoImpl mailimpl=new MailManagerDaoImpl();
	public Server(Socket s) {
		socket = s;
	}
	public static void open() {
		close_all = false;
	}
	public static void close() {
		close_all = true;
	}
	public void run() {
		PrintWriter pw = null;
		BufferedReader br = null;
		boolean ehlo = false;
		boolean auth = false;
		boolean mail = false;
		boolean rcpt = false;
		boolean data = false;
		String clientName = null;
		ArrayList<String> addrList = new ArrayList();
		String contents = null;
		User user = null;
		String rcptname = null;
		try {
			OutputStream os = socket.getOutputStream();
			pw = new PrintWriter(os, true);
			InputStreamReader is = new InputStreamReader(socket.getInputStream());
			br = new BufferedReader(is);
			pw.println("220 Wellcome to our email system");
			while (true) {
				if (close_all) {
					pw.println("221 server is closed!");
					break;
				}
				String input = br.readLine().toLowerCase();
				System.out.println(input);
				String[] commands = input.split(" ");
				if (commands[0].equals("quit")) {
					pw.println("221 Bye");
					break;
				}
				else {
					switch(commands[0]) { //check the commands
					
					case "ehlo":
					case "helo":
						if (commands.length != 2) pw.println("500 Error: bad syntax");
						else {
							clientName = commands[1];
							ehlo = true;
							pw.println("250 ok");
						}
						break;
					case "auth":
						if (!ehlo) pw.println("503 Error: send HELO/EHLO first");
						else if (auth) pw.println("503 Error: already authenticated");
						else if (commands.length !=2) pw.println("500 Error: bad syntax");
						else if (!commands[1].equals("login")) pw.println("504 Unrecognized authentication type");
						else {
							byte[] textByte = "username:".getBytes("UTF-8");
							pw.println("334 " + encoder.encodeToString(textByte));
							String ss = br.readLine();
							String name = new String(decoder.decode(ss), "UTF-8");       //get user name of base64_encode
							textByte = "Password:".getBytes("UTF-8");
							pw.println("334 " + encoder.encodeToString(textByte));
							ss = br.readLine();
							String passwd = new String(decoder.decode(ss), "UTF-8");    //get password of base64_encode
							List<User> u = userimpl.getUser(name);
							if (u.size()==1) { 
								user = u.get(0);
								if (name.equals(user.getUser_id()) && passwd.equals(user.getPassword())) {    //the user authentication API
									auth = true;
									pw.println("235 Authentication successful");
								}
								else pw.println("535 Error: authentication failed");
							}
						}
						break;
					case "mail":
						if (!ehlo) pw.println("503 Error: send HELO/EHLO first");
						else if (!auth) pw.println("553 authentication is required");
						else if (mail || rcpt) pw.println("503 bad sequence of commands");
						else if (commands.length !=2 || !Pattern.matches("^from:<[a-zA-z0-9_-]+@[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+)+>$", commands[1])) 
							pw.println("500 Error: bad syntax");
						else {
							int len = commands[1].length();
							String s1 = commands[1].substring(6, len-1);
							String[] sa = s1.split("@");
							String name = sa[0], domain = sa[1];
							if (!name.equals(user.getUser_id()) || !domain.equals(domainName))     //check your name and domain
								pw.println("553 Mail from must equal authorized user");
							else {
								mail = true;
								pw.println("250 Mail OK");
							}
						}
						break;
					case "rcpt":
						if (!ehlo) pw.println("503 Error: send HELO/EHLO first");
						else if (!auth) pw.println("553 authentication is required");
						else if (!mail) pw.println("503 bad sequence of commands");
						else if (commands.length !=2 || !Pattern.matches("^to:<[a-zA-z0-9_-]+@[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+)+>$", commands[1])) 
							pw.println("500 Error: bad syntax");
						else {
								int len = commands[1].length();
								String s1 = commands[1].substring(4, len-1);
								String[] sa = s1.split("@");
								String name = sa[0], domain = sa[1];
								if (userimpl.isUser(name) && domain.equals(domainName)) {
									rcpt = true;
									addrList.add(name);
									pw.println("250 Mail OK");
								}
								else {
									pw.println("503 address is illegal");
								}
						}
						break;
					case "data":
						if (!ehlo) pw.println("503 Error: send HELO/EHLO first");
						else if (!auth) pw.println("553 authentication is required");
						else if (!mail || !rcpt) pw.println("503 bad sequence of commands");
						else {
							pw.println("354 End data with <CR><LF>.<CR><LF>");
							contents = "";
							while (true) {
								String s1 = br.readLine();
								if (s1.equals(".")) {
									/*
									 * mail send to destination
									 * add mail to the mail send queue
									 */
									Mail mymail=new Mail();
									mymail.setContent(contents);
									mymail = mailimpl.addMail(mymail);
									mailimpl.addMailofUser(user.getUser_id(), mymail.getMail_id());
									for (String s : addrList) {
										mailimpl.addMailofUser(s, mymail.getMail_id());
									}
									pw.println("250 Mail OK");
									mail = false;
									rcpt = false;
									break;
								}
								else contents = contents + s1 + "\r\n";
							}
							System.out.println(contents);
						}
						break;
					default:
						pw.println("502 Error: command not implemented");
						
					}// check commands end
				}
				
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			if (br != null) br.close();
			if (pw != null) pw.close();
			if (socket != null) socket.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}
